﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using System.IO;
using log4net.Config;
using log4net;
using log4net.Repository;

namespace YasharEl.Infrastructure.Diagnostics.Logging.Log4Net
{
    public class Log4netLoggerFactory : ILoggerFactory
    {
        #region Fields

        private string _factoryName;

        #endregion

        #region ILoggerFactory Implementations

        public ILogger Create(Type type)
        {
            Type log4netLoggerOpenGenericType = typeof(Log4netLogger<>);

            // TODO: Check that type is open generic type
            // If this open generic type or partial closed generic type CreateInstance fails.
            Type log4netLoggerClosedGenericType = log4netLoggerOpenGenericType.MakeGenericType
                (
                    new Type[] { type }
                );
            ILog log = null;
            if (!string.IsNullOrEmpty(_factoryName))
            {
                log = LogManager.GetLogger(_factoryName, type);
            }
            else
            {
                log = LogManager.GetLogger(type);
            }
            return (ILogger)Activator.CreateInstance
                (
                    log4netLoggerClosedGenericType,
                    new object[] 
                    { 
                        log
                    }
                );
        }

        public ILogger Create(string name)
        {
            if (!string.IsNullOrEmpty(_factoryName))
            {
                return new Log4netLogger(LogManager.GetLogger(_factoryName, name));
            }
            return new Log4netLogger(LogManager.GetLogger(name));
        }

        public bool InitializeLoggingFactory(string configFilename, string factoryName)
        {
            _factoryName = factoryName;
            if (!Path.IsPathRooted(configFilename))
            {
                configFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, configFilename);
            }

            FileInfo configFile = new FileInfo(configFilename);

            if (!configFile.Exists)
            {
                throw new InvalidSystemConfigurationException(string.Format("Could not configure log4net component.Given file {0} not exists.", configFilename));
            }

            if (!string.IsNullOrEmpty(_factoryName))
            {
                ILoggerRepository repository = LogManager.CreateRepository(_factoryName);
                XmlConfigurator.ConfigureAndWatch(repository, configFile);
            }
            else
            {
                XmlConfigurator.ConfigureAndWatch(configFile);
            }

            return true;
        }

        #endregion
    }
}
